﻿using UnityEngine;
using System;
using System.Collections;
using Kinect2;

public class InfraredBasic : MonoBehaviour {

	KinectSensor kinectSensor;
	InfraredFrameReader infraredFrameReader;
	FrameDescription infraredFrameDescription;
	Texture2D texture;
	GameObject status;
	const float InfraredSourceValueMaximum = (float)ushort.MaxValue;
	const float InfraredSourceScale = 0.75f;
	const float InfraredOutputValueMinimum = 0.01f;
	const float InfraredOutputValueMaximum = 1.0f;

	void Start () 
	{
		kinectSensor = KinectSensor.GetDefault();
		
		infraredFrameReader = kinectSensor.InfraredFrameSource.OpenReader();
		infraredFrameReader.FrameArrived += Reader_InfraredFrameArrived;
		
		infraredFrameDescription = kinectSensor.InfraredFrameSource.FrameDescription;
		texture = new Texture2D(infraredFrameDescription.Width, infraredFrameDescription.Height, TextureFormat.BGRA32, false);
		
		kinectSensor.IsAvailableChanged += Sensor_IsAvailableChanged;
		kinectSensor.Open();
		
		InitializeComponent();
	}
	
	void Update () 
	{
		EventRouter.Check();
	}
	
	void OnApplicationQuit()
	{
		if (infraredFrameReader != null)
			infraredFrameReader.Dispose();
		infraredFrameReader = null;
		
		if (kinectSensor != null)
			kinectSensor.Close ();
		kinectSensor = null;
	}
	
	void InitializeComponent()
	{
		GameObject infrared = GameObject.Find("infrared");
		infrared.guiTexture.texture = texture;
		status = GameObject.Find("status");
		status.guiText.text = kinectSensor.IsAvailable ? "Running" : "No ready Kinect found!";
	}

	void Reader_InfraredFrameArrived(object sender, InfraredFrameArrivedEventArgs e)
	{
		using (InfraredFrame infraredFrame = e.FrameReference.AcquireFrame())
		{
			if (infraredFrame != null)
			{
				using (KinectBuffer infraredBuffer = infraredFrame.LockImageBuffer())
				{
					if (((infraredFrameDescription.Width * infraredFrameDescription.Height) == (infraredBuffer.Size / infraredFrameDescription.BytesPerPixel)) &&
					    (infraredFrameDescription.Width == texture.width) && (infraredFrameDescription.Height == texture.height))
					{
						ProcessInfraredFrameData(infraredBuffer.UnderlyingBuffer, infraredBuffer.Size);
					}
				}
			}
		}
	}

	unsafe void ProcessInfraredFrameData(IntPtr infraredFrameData, uint infraredFrameDataSize)
	{
		ushort* data = (ushort*)infraredFrameData;
		int width = texture.width;
		int height = texture.height;
		byte[] data2 = new byte[width * height * 4];
		for (int j = 0; j < height; j++){
			int dst = width * 4 * (height - 1 - j);
			for (int i = 0; i < width; i++) {
				ushort d = (*data++);
				byte intensity =(byte)(255 * Math.Min(InfraredOutputValueMaximum, (((float)d / InfraredSourceValueMaximum * InfraredSourceScale) * (1.0f - InfraredOutputValueMinimum)) + InfraredOutputValueMinimum));
				data2[dst + i * 4] = intensity;
				data2[dst + i * 4 + 1] = intensity;
				data2[dst + i * 4 + 2] = intensity;
				data2[dst + i * 4 + 3] = 0xff;
			}
		}
		texture.LoadRawTextureData (data2);
		texture.Apply();
	}
	
	void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e)
	{
		status.guiText.text = kinectSensor.IsAvailable ? "Running" : "Kinect not available!";
	}
	
}
